package com.example.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.example.entity.User;
import lombok.extern.slf4j.Slf4j;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;


@Slf4j
public class JwtUtil {

    private static final long EXPIRE_TIME = 2 ; //指定一个token过期时间（小时）
    private static final String SECRET_KEY ="yizuxuan"; //密钥
    private static final String TOKEN_PREFIX = "Bearer ";

    public static String createBearerToken(User user) {
        Date expireTime = new Date(System.currentTimeMillis() + EXPIRE_TIME * 1000 * 60 *60);
        Algorithm algorithm = Algorithm.HMAC256(SECRET_KEY);    //使用密钥进行哈希
        // 附带username信息的token
        return TOKEN_PREFIX + JWT.create()
                .withClaim("id",user.getId())
                .withClaim("username", user.getUsername())
                .withClaim("roles", user.getRole())
                .withExpiresAt(expireTime)  //过期时间
                .sign(algorithm);     //签名算法
    }

    //给过期token用来刷新token
    public static String createBearerToken(DecodedJWT decodedToken) {
        Date expireTime = new Date(System.currentTimeMillis() + EXPIRE_TIME * 1000 * 60 *60);
        Algorithm algorithm = Algorithm.HMAC256(SECRET_KEY);    //使用密钥进行哈希
        // 附带username信息的token
        return TOKEN_PREFIX + JWT.create()
                .withClaim("id", decodedToken.getClaim("id").asString())
                .withClaim("username", decodedToken.getClaim("username").asString())
                .withClaim("roles", decodedToken.getClaim("roles").asList(Long.class))
                .withExpiresAt(expireTime)  //过期时间
                .sign(algorithm);     //签名算法
    }

    /**
     * 校验token是否正确
     */
    public static boolean verifyToken(String token) throws TokenExpiredException {//user要从sercurityManager拿，确保用户用的是自己的token
        //根据密钥生成JWT效验器
        Algorithm algorithm = Algorithm.HMAC256(SECRET_KEY);
        JWTVerifier verifier = JWT.require(algorithm)
                .withClaim("username", getUsername(token))//从不加密的消息体中取出username
                .withClaim("roles",getRoles(token))
                .build();
        //生成的token会有roles的Claim，这里不加不知道行不行。
        // 一个是直接从客户端传来的token，一个是根据盐和用户名等信息生成secret后再生成的token
        verifier.verify(token);
        //能走到这里
        return true;

    }

    //去掉Bearer前缀
    public static String removePrefixIfExists(String token) {
        String[] s = token.split(" ");
        return s[0].equals("Bearer")? s[1]:s[0];
    }

    /**
     * 在token中获取到username信息
     */
    public static String getUserId(String bearerToken) {
        String token = removePrefixIfExists(bearerToken);
        DecodedJWT jwt = JWT.decode(token);
        return jwt.getClaim("id").asString();
    }

    public static String getUsername(String bearerToken) {
        String token = removePrefixIfExists(bearerToken);
        DecodedJWT jwt = JWT.decode(token);
        return jwt.getClaim("username").asString();
    }

    public static String getRoles(String bearerToken) {
        String token = removePrefixIfExists(bearerToken);
        DecodedJWT jwt = JWT.decode(token);
        return jwt.getClaim("roles").asString();
    }

    public static User getUserFromToken(String bearerToken) {
        String token = removePrefixIfExists(bearerToken);
        User user = new User();
        DecodedJWT jwt = JWT.decode(token);
        user.setUsername(jwt.getClaim("username").asString());
        user.setRole(jwt.getClaim("roles").asList(Long.class));
        return user;
    }

    public static Map<String,Object> getMapFromToken(String bearerToken) {
        String token = removePrefixIfExists(bearerToken);
        DecodedJWT jwt = JWT.decode(token);
        HashMap<String, Object> map = new HashMap<>();
        map.put("username",jwt.getClaim("username").asString());
        map.put("roles",jwt.getClaim("roles").asList(Long.class));
        return map;
    }

    /**
     * 判断是否过期
     */
    public static boolean isExpire(String bearerToken) {
        String token = removePrefixIfExists(bearerToken);
        DecodedJWT jwt = JWT.decode(token);
        return jwt.getExpiresAt().getTime() < System.currentTimeMillis();
    }

    /**
     * 传入旧的token刷新token
     */
    public static String refreshToken(String bearerToken) throws Exception {
        String token = removePrefixIfExists(bearerToken);
        if(token==null){
            throw new NullPointerException();
        } else {
            DecodedJWT decodedJWT = JWT.decode(token);
            return createBearerToken(decodedJWT);
        }
    }


}

